import '../../css/canvas.css';
import __DB__               from '../db/index.js';
import __tool__             from '../tool/index.js';
import __cntMenu__          from '../cntMenu/index.js';
import __customEvent__      from '../customEvent/index.js';
import __drag__             from '../drag/index.js';
import __opt__              from '../opt/index.js';
import __line__             from '../line/index.js';

class canvasClass {
    constructor(){
        this.main               = null; // 容器
        this.canvas             = null; // 画布
        this.canvasLineEl       = null; // 线的画布
        this.canvasLineTestEl   = null; // 引导线的画布
        this.infiniteScale      = 10;   // 无限画布比例
        this.scale              = 1;    // 缩放
        this.scaleRange         = {     // 缩放范围
            max : 1.9,
            min : 0.2,
        };
        this.mainWidht          = 0;    // 容器宽度
        this.mainHeight         = 0;    // 容器高度
        this.canvasWidth        = 0;    // 画布宽度
        this.canvasHeight       = 0;    // 画布高度

        this.space_x            = 100;  // 节点之间横向间隙
        this.space_y            = 20;   // 节点之间纵向间隙

        this.nodeStyleInit = {
            rule        : {icon:"",cls:""},
            compute     : {icon:"",cls:""},
            resource    : {icon:"",cls:""},
            general     : {icon:"",cls:""},
        };
        this.begin_xy = [];// 初始XY值
        this.hawkEyeObj = {       // 鹰眼
            open:false,
            pid:null,
        };

        this.eye = {
            el:null,
            box:null,
            scaleW:null,
            scaleH:null,
        };
    }

    init(res){
        this.main = res.el;
        this.main.setAttribute('class','xMain');
        this.main.setAttribute('tabindex','0');

        this.canvas = document.createElement('div');
        this.canvas.setAttribute('id','xCanvas');
        this.canvas.setAttribute('class','xmd-canvas');
        this.canvas.setAttribute('tabindex','0');

        this.main.appendChild(this.canvas);

        let span_x = __DB__.publicData.style.node.space_x||this.space_x,
            span_y = __DB__.publicData.style.node.space_y||this.space_y;

        this.space_x = span_x||this.space_x;
        this.space_y = span_y||this.space_y;

        this.autoSize();                        // 自适应容器的尺寸
        this.InfiniteCanvas();                  // 无限画布
        this.evt();                             // 画布事件
        __customEvent__.register();             // 注册自定义事件        
    }

    // 定位到根节点
    localRoot(){
        this.canvas.style.left  = -this.begin_xy[0] + "px";
        this.canvas.style.top   = -this.begin_xy[1] + "px";

        this.canvasLineEl.style.left  = -this.begin_xy[0] + "px";
        this.canvasLineEl.style.top   = -this.begin_xy[1] + "px";

        this.canvasLineTestEl.style.left  = -this.begin_xy[0] + "px";
        this.canvasLineTestEl.style.top   = -this.begin_xy[1] + "px";
    }

    setScale(num){
        this.scale = num;
        this.canvas.style.transform             = `scale(${num})`;
        this.canvasLineEl.style.transform       = `scale(${num})`;
        this.canvasLineTestEl.style.transform   = `scale(${num})`;
    }

    getScale(){
        return this.scale;
    }

    // 自适应容器的尺寸
    autoSize(){
        let w = parseInt(this.main.getBoundingClientRect().width),
            h = parseInt(this.main.getBoundingClientRect().height);

        let w_p = __DB__.publicData.width;
        let h_p = __DB__.publicData.height;

        w = w_p||w;
        h = h_p||h;
        // this.main.style.width  = w + "px";
        // this.main.style.height = h + "px";

        let m = this.infiniteScale;//无限画布比例 例m=2 2倍于容器大小

        this.begin_xy = [(w*m-w)/2,(h*m-h)/2];

        this.mainWidht      = w;
        this.mainHeight     = h;
        this.canvasWidth    = w*m;
        this.canvasHeight   = h*m;

        this.canvas.style.cssText = `
            top:-${(h*m-h)/2}px;
            left:-${(w*m-w)/2}px;
            width:${w*m}px;
            height:${h*m}px;
            transform:scale(${this.scale});
        `;
    }

    // 无限画布
    InfiniteCanvas(){
        this.canvas.onmousedown = (e)=>{
            if(e.button === 2)return;
            //获取鼠标按下的坐标
            let x1 = e.clientX,
                y1 = e.clientY;
            
            let nowX = e.target.offsetLeft,
                nowY = e.target.offsetTop;
            
            let open = this.hawkEyeObj.open
            // 获取鹰眼当前位置
            let demo_x1,demo_y1;
            if(open){
                demo_x1 = parseFloat(this.eye.box.style.left)||25;
                demo_y1 = parseFloat(this.eye.box.style.top)||25;
            }

            //给可视区域添加鼠标的移动事件
            document.onmousemove = (ev)=>{
                document.body.style.cursor='move';
                //获取鼠标移动时的坐标
                let x2 = ev.clientX;
                let y2 = ev.clientY;

                //计算出鼠标的移动距离
                let x = x2 - x1;
                let y = y2 - y1;

                this.x = x;
                this.y = y;

                // 鹰眼自适应
                if(open){
                    let eye_x = demo_x1 - (x)/this.eye.scaleW;
                    let eye_y = demo_y1 - (y)/this.eye.scaleH;
                    this.eye.box.style.left = eye_x + "px";
                    this.eye.box.style.top  = eye_y + "px";
                    if(this.canvasLineEl)this.canvasLineEl.style.left = eye_x + "px";
                    if(this.canvasLineEl)this.canvasLineEl.style.top  = eye_y + "px";
                    if(this.canvasLineTestEl)this.canvasLineTestEl.style.left = eye_x + "px";
                    if(this.canvasLineTestEl)this.canvasLineTestEl.style.top  = eye_y + "px";
                }

                this.canvas.style.left = (nowX + x) + "px";
                this.canvas.style.top  = (nowY + y) + "px";
                if(this.canvasLineEl)this.canvasLineEl.style.left = (nowX + x) + "px";
                if(this.canvasLineEl)this.canvasLineEl.style.top  = (nowY + y) + "px";
                if(this.canvasLineTestEl)this.canvasLineTestEl.style.left = (nowX + x) + "px";
                if(this.canvasLineTestEl)this.canvasLineTestEl.style.top  = (nowY + y) + "px";


                // 绑定自定义事件
                __customEvent__.set({
                    type:"canvasDrag",
                    data:{
                        left:(nowX + x),
                        top:(nowY + y)
                    }
                });
            };

            document.onmouseup = (ev)=>{
                document.onmousemove = null;
                document.onmouseup   = null;
                document.body.style.cursor='default';
            };
        }

        this.main.onmousewheel = (e)=>{
            let max = this.scaleRange.max,
                min = this.scaleRange.min;
            if(e.wheelDelta > 0){
                if(this.scale > max)return;
                this.scale = parseFloat(this.scale) + 0.1;
                this.scale = this.scale.toFixed(1);
            }
            else{
                if(this.scale <= min)return;
                this.scale = parseFloat(this.scale) - 0.1;
                this.scale = this.scale.toFixed(1);
            }
            
            // 绑定自定义事件
            __customEvent__.set({
                type:"scaleChange",
                data:{
                    sacle:this.scale
                }
            });

            // this.maincaleOut = this.maincale;
            this.canvas.style.transform = `scale(${this.scale})`;
            if(this.canvasLineEl)this.canvasLineEl.style.transform = `scale(${this.scale})`;
            if(this.canvasLineTestEl)this.canvasLineTestEl.style.transform = `scale(${this.scale})`;
        }
    }

    // 创建额外画布
    createCanvas(type){
        if(!type)return;

        if(type === "canvasLine"){
            let canvasTestLineOld = document.getElementById('canvasTestLine');
            if(canvasTestLineOld)canvasTestLineOld.remove();
            if(this.canvasLineEl)this.canvasLineEl.remove();
            let canvasLineEl = this.canvas.cloneNode();
            canvasLineEl.setAttribute('class','canvasLine')
            canvasLineEl.setAttribute('id','canvasLine')
            this.canvasLineEl = canvasLineEl;
            this.main.appendChild(canvasLineEl);

            let canvasLineTestEl = this.canvas.cloneNode();
            canvasLineTestEl.setAttribute('class','canvasTestLine');
            canvasLineTestEl.setAttribute('id','canvasTestLine');
            this.canvasLineTestEl = canvasLineTestEl;
            this.main.appendChild(canvasLineTestEl);

            __line__.canvasInit();// 初始化画线需要的画布
        }
        
    }

    // 清除画布内容
    clear(){
        this.canvas.innerHTML = "";
    }

    // 移除画布
    del(){
        this.main.innerHTML = "";
    }

    // 重置节点
    reset(res){
        let type  = res.type || 'all',
            nodes = res.nodes,
            fn    = res.fn||null;
            
        next_all.call(this);

        function next_all(){
            let nodeEls = [];
            for(let k in nodes){
                let nEl = this.node(nodes[k]);
                nodeEls.push(nEl);
            }
            
            this.clear();
            this.createCanvas('canvasLine');// 创建额外画布
            
            if(nodeEls.length === 0)return;
            for(let el of nodeEls){
                this.canvas.appendChild(el);
                this.nodePoi(el);
            }

            __drag__.use();

            this.canvas.style.transform = `scale(${this.scale})`;
            if(this.canvasLineEl)this.canvasLineEl.style.transform = `scale(${this.scale})`;
            if(this.canvasLineTestEl)this.canvasLineTestEl.style.transform = `scale(${this.scale})`;
            fn&&fn();
        }

    }

    // 节点模板
    node(res){
        // 自定义节点样式
        let id              = res.id,                   // 节点id
            label           = res.label,                // 节点标题
            root            = res.root,                 // 是否是根节点
            flip            = res.flip,                 // 是否翻转
            status          = res.status,               // 节点运行状态
            nodeLimit       = res.style.limit,          // 节点标题长度
            nodeIcon        = res.style.icon,           // 节点图标
            nodeCls         = res.style.cls,            // 节点不同类型的样式
            priority        = res.style.priority,       // 优先级
            html            = res.html,                 // 自定义新内容HTML
            divClass        = res.divClass||[],         // 自定义节点样式
            divColor        = res.divColor||"",         // 自定义字体颜色
            divBgColor      = res.divBgColor||"",       // 自定义背景字体颜色
            index           = parseInt(res.node.index); // 索引      

        let nodeDiv = document.createElement('div');
        nodeDiv.setAttribute('id',id);
        nodeDiv.classList.add('xmd-node');

        // 初始化-获取和设置所有节点的class
        let nodePulicClass = __DB__.publicData.style.node.class;
        nodePulicClass&&nodeDiv.classList.add(nodePulicClass);

        // 初始化-获取和设置所有节点的class
        let nodePulicCls = __DB__.publicData.style.node.cls;
        if(nodePulicCls.length > 0){
            for(let el of nodePulicCls){
                if(el.id === id){
                    el.class&&nodeDiv.classList.add(el.class);
                    break;
                }
            }
        }
        
        nodeCls&&nodeDiv.classList.add(nodeCls);// 节点单独设置
        root&&nodeDiv.classList.add('xmd-node-root');

        let nodeMain    = htmlMain();
        let nodeOpt     = document.createElement('div');
        let nodeIn      = document.createElement('div');
        let nodeUp      = document.createElement('div');
        let nodeDown    = document.createElement('div');
        let nodeHtml    = document.createElement('div');
        let nodePull    = htmlPull();
        let nodeLoading = document.createElement('div');

        nodeDiv.appendChild(nodeMain);
        nodeDiv.appendChild(nodePull);

        // 自定义新内容HTML
        nodeHtml.classList.add('node-html');
        nodeHtml.innerHTML = html;
        nodeDiv.appendChild(nodeHtml);

        // 可被操作模块
        nodeOpt.classList.add('xmd-node-opt');
        nodeDiv.appendChild(nodeOpt);

        // 可响应的模块-上
        nodeUp.classList.add('xmd-node-up');
        nodeDiv.appendChild(nodeUp);

        // 可响应的模块-中
        nodeIn.classList.add('xmd-node-in');
        nodeDiv.appendChild(nodeIn);

        // 可响应的模块-下
        nodeDown.classList.add('xmd-node-down');
        nodeDiv.appendChild(nodeDown);

        // 自定义样式
        if(divClass.length > 0){
            for(let el of divClass){
                nodeDiv.classList.add(el);
            }
        }

        // 加载中
        nodeLoading.classList.add('xmd-node-loading');
        let nodeLoadingMain = document.createElement('div');
        nodeLoadingMain.classList.add('xmd-node-loadingMain');
        nodeLoading.classList.add('xmd-node-loading-hide');
        if(root)nodeLoadingMain.classList.add('xmd-node-loadingMainRoot');
        nodeLoadingMain.innerHTML = `
            <span></span>
            <span></span>
            <span></span>
            <span></span>
            <span></span>
        `;
        nodeLoading.appendChild(nodeLoadingMain);
        nodeDiv.appendChild(nodeLoading);        

        return nodeDiv;

        function htmlMain(){
            let mainEl = document.createElement('div');
            mainEl.classList.add('xmd-node-main');
            mainEl.classList.add('zoom');

            if(divBgColor)mainEl.style.backgroundColor = divBgColor;

            let iconEl = htmlIcon();// 图标模块
            let txtEl  = htmlTxt();// 显示文本模块
            mainEl.appendChild(iconEl);
            mainEl.appendChild(txtEl);

            let statusEl = document.createElement('div');

            // 节点状态模块
            if(status !== -1){
                let cls = "";
                if(status === 2){  
                    cls = __DB__.publicData.nodeStateCls.fail;
                }
                else if(status === 0){
                    cls = __DB__.publicData.nodeStateCls.ing;
                }
                else if(status === 1){
                    cls = __DB__.publicData.nodeStateCls.success;
                }
                if(cls){
                    statusEl.classList.add('xmd-node-status');
                    statusEl.classList.add(cls);
                }

                mainEl.appendChild(statusEl);
            }

            return mainEl;

            // 图标模块
            function htmlIcon(){
                // 创建图标模块
                let iconEl = document.createElement('div');
                iconEl.classList.add('xmd-node-icon');
                nodeIcon&&iconEl.classList.add(nodeIcon);

                // 创建索引
                let nodeIndex = document.createElement('div');
                nodeIndex.classList.add('xmd-nodeIndex');
                index = index>9?index:'0'+index;
                index = index>99?99:index;
                nodeIndex.innerHTML = index;

                // 创建优先级
                let nodePriority = document.createElement('div');
                nodePriority.classList.add('xmd-nodePriority');
                nodePriority.classList.add('xmd-nodePriority-mpd');                
                let nodePriorityP = document.createElement('div');
                nodePriorityP.classList.add('xmd-nodePriority-p');
                // 获取优化级-渲染不同的颜色
                let nodePriorityTxt = 'M';
                if(priority == 0){
                    nodePriorityP.classList.add('xmd-nodePriority-l');
                    nodePriorityTxt = 'L';
                }
                else if(priority == 1){
                    nodePriorityP.classList.add('xmd-nodePriority-m');
                    nodePriorityTxt = 'M';
                }
                else if(priority == 2){
                    nodePriorityP.classList.add('xmd-nodePriority-h');
                    nodePriorityTxt = 'H';
                }
                nodePriorityP.innerHTML = nodePriorityTxt;
                nodePriority.appendChild(nodePriorityP);

                iconEl.appendChild(nodeIndex);
                iconEl.appendChild(nodePriority);

                return iconEl;
            }

            // 显示文本模块
            function htmlTxt(){
                let txtEl = document.createElement('div');
                txtEl.classList.add('xmd-node-txt');
                
                if(root){
                    txtEl.innerHTML = label;
                }else{
                    let txtMainEl = document.createElement('div');
                    txtMainEl.classList.add('xmd-node-txtMain');
                    let txtMainElSpan = document.createElement('span');
                    txtMainElSpan.innerHTML = label;

                    if(divColor)txtMainElSpan.style.color = divColor;
                    
                    txtMainEl.appendChild(txtMainElSpan);
                    txtEl.appendChild(txtMainEl);
                }

                txtEl.style.width = nodeLimit + "px";

                return txtEl;
            }
        }

        function htmlPull(){
            let pullEl = document.createElement('div');
            pullEl.setAttribute('class','xmd-node-pull');
            let pullL = document.createElement('div');
                pullL.setAttribute('class','pull-left');

            let pullR = document.createElement('div');
                pullR.setAttribute('class','pull-right');
            if(root){
                pullEl.appendChild(pullL);
                pullEl.appendChild(pullR);
            }
            else{
                if(flip){
                    pullEl.appendChild(pullL);
                }
                else{
                    pullEl.appendChild(pullR);
                }
            }
            return pullEl;
        }
        
    }

    // 节点坐标
    nodePoi(el){
        let n_w = el.getBoundingClientRect().width,
            n_h = el.getBoundingClientRect().height,
            id  = el.getAttribute('id');

        n_w = n_w/this.scale;
        n_h = n_h/this.scale;

        let node = __DB__.get(id);

        if(!node.node.init)return;
        node.node.init.size = {
            w:n_w,
            h:n_h,
        }

        node.node.init.size = {
            w:n_w,
            h:n_h,
        }

        if(el.getAttribute('id') === "root"){
            let x = this.canvasWidth/2 - n_w/2,
                y = this.canvasHeight/2 - n_h/2;
            el.style.left = `${x}px`;
            el.style.top  = `${y}px`;
            
            node.node.init.poi = {x,y};

            let itp = __tool__.idTrunPoi(id);//获取节点坐标信息
            node.node.init.point = itp.point;

            __DB__.set(id,node);
        }

    }

    // 获取节点列表
    getNodeEls(){
        let nodes = document.querySelectorAll('.xmd-node');
        return nodes;
    }

    // 获取节点列表
    getNodeOptEls(){
        let nodes = document.querySelectorAll('.xmd-node-opt');
        return nodes;
    }

    // 鹰眼
    hawkEye(){
        let open = this.hawkEyeObj.open,
            pid  = this.hawkEyeObj.pid;

        fn_remove.call(this);
        if(open)fn_create.call(this);

        function fn_remove(){
            let el = document.getElementById('eye');
            if(el)el.remove();
            
            if(this.eye.box){
                this.eye.box.style.left = "25px";
                this.eye.box.style.top  = "25px";
                this.x = null;
                this.y = null;

                // if(this.canvas_x){
                //     this.canvas.style.left = this.canvas_x + "px";
                //     this.canvas.style.top  = this.canvas_y + "px";
                // }
            }
        }

        function fn_create(){
            let canvas = document.querySelector("#xCanvas");
            let canvas_w = canvas.getBoundingClientRect().width;
            let canvas_h = canvas.getBoundingClientRect().height;

            let el_eye_box = document.createElement('div');
            el_eye_box.setAttribute('id','eyeBox');
            el_eye_box.setAttribute('class','eyeBoxCls');

            let el_eye = document.createElement('div');
            el_eye.setAttribute('id','eye');
            el_eye.setAttribute('class','eyeCls');
            el_eye.innerText = "";
            el_eye.appendChild(el_eye_box);
            let el_s = this.main;
            if(pid){
                el_s = document.getElementById(pid);
                if(el_s){
                    let w = el_s.getBoundingClientRect().width;
                    let h = el_s.getBoundingClientRect().height + 10;
                    let boxLeft = el_s.offsetLeft - 75;
                    el_eye.style.left = boxLeft + "px";
                    el_eye.style.top = (el_s.offsetTop + h) + "px";
                }
            };
            el_s = el_s||this.main;
            document.body.appendChild(el_eye);

            let el_eye_box_w = el_eye_box.getBoundingClientRect().width;
            el_eye_box_w = el_eye_box_w*this.infiniteScale;
            let el_eye_box_h = el_eye_box.getBoundingClientRect().height;
            el_eye_box_h = el_eye_box_h*this.infiniteScale;
            // let eyeScaleW = canvas_w/el_eye_box_w;
            // let eyeScaleH = canvas_h/el_eye_box_h;
            let eyeScaleW = canvas_w/el_eye_box_w;
            let eyeScaleH = canvas_h/el_eye_box_h;
            this.eye.scaleW = eyeScaleW;
            this.eye.scaleH = eyeScaleH;

            this.eye.box = el_eye_box;
            this.eye.el = el_eye;

            if(this.canvas_x){
                this.canvas.style.left = this.canvas_x + "px";
                this.canvas.style.top  = this.canvas_y + "px";
                if(this.canvasLineEl)this.canvasLineEl.style.left = this.canvas_x + "px";
                if(this.canvasLineEl)this.canvasLineEl.style.top  = this.canvas_y + "px";
                if(this.canvasLineTestEl)this.canvasLineTestEl.style.left = this.canvas_x + "px";
                if(this.canvasLineTestEl)this.canvasLineTestEl.style.top  = this.canvas_y + "px";
            }

            let demo111_x1 = parseFloat(this.eye.box.style.left)||25;
            let demo111_y1 = parseFloat(this.eye.box.style.top)||25;
            let eye_x = demo111_x1 - (this.x)/this.eye.scaleW;
            let eye_y = demo111_y1 - (this.y)/this.eye.scaleH;
            this.eye.box.style.left = eye_x + "px";
            this.eye.box.style.top  = eye_y + "px";

            el_eye.ondblclick = (e)=>{
                e.stopPropagation();
                e.preventDefault();
                this.canvas.style.left = this.canvas_x + "px";
                this.canvas.style.top  = this.canvas_y + "px";
                if(this.canvasLineEl)this.canvasLineEl.style.left = this.canvas_x + "px";
                if(this.canvasLineEl)this.canvasLineEl.style.top  = this.canvas_y + "px";
                if(this.canvasLineTestEl)this.canvasLineTestEl.style.left = this.canvas_x + "px";
                if(this.canvasLineTestEl)this.canvasLineTestEl.style.top  = this.canvas_y + "px";
                el_eye_box.style.left = "25px";
                el_eye_box.style.top  = "25px";
                this.x = null;
                this.y = null;
            }

            el_eye_box.onmousedown = (e)=>{
                e.stopPropagation();
                e.preventDefault();
                let l  = e.target.offsetLeft,
                    t  = e.target.offsetTop,
                    x1 = e.clientX,
                    y1 = e.clientY;
                
                let demo_x1 = parseFloat(this.canvas.style.left);
                let demo_y1 = parseFloat(this.canvas.style.top);

                document.onmousemove = (ev)=>{
                    let x2 = ev.clientX;
                    let y2 = ev.clientY;
                    let eye_x = l + x2 - x1;
                    let eye_y = t + y2 - y1;
                    el_eye_box.style.left = eye_x + "px";
                    el_eye_box.style.top  = eye_y + "px";

                    let xxx = demo_x1 - (x2 - x1)*eyeScaleW;
                    let yyy = demo_y1 - (y2 - y1)*eyeScaleH;

                    // this.canvas.style.left = (demo_x1 - (x2 - x1)*eyeScaleW) + "px";
                    // this.canvas.style.top  = (demo_y1 - (y2 - y1)*eyeScaleH) + "px";
                    this.canvas.style.left = xxx + "px";
                    this.canvas.style.top  = yyy + "px";
                    if(this.canvasLineEl)this.canvasLineEl.style.left = (demo_x1 - (x2 - x1)*eyeScaleW) + "px";
                    if(this.canvasLineEl)this.canvasLineEl.style.top  = (demo_y1 - (y2 - y1)*eyeScaleH) + "px";
                    if(this.canvasLineTestEl)this.canvasLineTestEl.style.left = (demo_x1 - (x2 - x1)*eyeScaleW) + "px";
                    if(this.canvasLineTestEl)this.canvasLineTestEl.style.top  = (demo_y1 - (y2 - y1)*eyeScaleH) + "px";
                }

                document.onmouseup = (ev)=>{
                    document.onmousemove = null;
                    document.onmouseup   = null;
                }
            }
        }

        
    }

    // 事件
    evt(){
        this.canvas.oncontextmenu = (e)=>{
            e.stopPropagation();
            e.preventDefault();

            __cntMenu__.x = e.clientX;
            __cntMenu__.y = e.clientY;   
            
            __customEvent__.set({
                type:"cntMenuCanvas",
                data:{}
            })
            
            __cntMenu__.init({
                type:"canvas",
                e,
                x:e.clientX,
                y:e.clientY,
            });
        }
    }
}

let canvas = new canvasClass();
export default canvas;